package com.cakebackoffice.Model;

import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import com.cakebackoffice.clientsoap.CakeBackOfficeSoapClient;
import com.cakebackoffice.clientsoap.contract.LocalPriceHT;
import com.cakebackoffice.clientsoap.contract.ProductType;
import com.cakebackoffice.database.DataSource;
import com.cakebackoffice.database.IDatabasable;
import com.cakebackoffice.database.OrderTable;
import com.cakebackoffice.database.Order_has_UnitarySale;

import java.util.*;

public class Order implements IDatabasable {
    private Long idDB = null;
    private Long remoteID;
    private Client client = null;
    private Place deliveryPlace = null;
    private Place invoicingPlace = null;
    private List<UnitarySale> unitarySaleList = new ArrayList<UnitarySale>();
    private Date orderDate = null;
    private Date deliveryDate = null;
    private boolean isTracked;
    private String corporateComments = null;
    private PaymentType paymentType = null;
    private DeliveryType deliveryType = null;
    private List<OrderLine> orderLines = new ArrayList<OrderLine>();

    public Order(Client client, Address address, List<UnitarySale> unitarySaleList, Date orderDate) {
        this.client = client;
        this.deliveryPlace = new Place(address);
        this.unitarySaleList = unitarySaleList;
        this.orderDate = orderDate;
    }

    private Order(DataSource dataSource, Cursor cursor) {
        idDB = cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.ID));
        setRemoteID(cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.REMOTE_ID)));
        client = Client.getOne(dataSource, cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.ID_CLIENT)));
        isTracked = (cursor.getInt(cursor.getColumnIndexOrThrow(OrderTable.ISTRACKED)) == 1);
        corporateComments = cursor.getString(cursor.getColumnIndexOrThrow(OrderTable.CORPORATECOMMENTS));
        deliveryPlace = Place.getOne(dataSource, cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.ID_DELIVERYPLACE)));
        invoicingPlace = Place.getOne(dataSource, cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.ID_BILLINGPLACE)));
        orderDate = new Date(cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.DATE)));
        deliveryDate = new Date(cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.DELIVERYDATE)));
        paymentType = PaymentType.getOne(dataSource, cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.ID_DELIVERYTYPE)));
        deliveryType = DeliveryType.getOne(dataSource, cursor.getLong(cursor.getColumnIndexOrThrow(OrderTable.ID_DELIVERYTYPE)));


        //Recuperer les ids des Produits
        Cursor cursorp = dataSource.getMore(this, Order_has_UnitarySale.getInstance(), Order_has_UnitarySale.ID_ORDER);
        cursorp.moveToFirst();
        while (!cursorp.isAfterLast()) {
            UnitarySale u = UnitarySale.getOne(dataSource, cursorp.getLong(cursorp.getColumnIndexOrThrow(Order_has_UnitarySale.ID_UNITARY_SALE)));
            if (u != null) {
                this.unitarySaleList.add(u);
            }
            cursorp.moveToNext();
        }
    }

    public Order(Context context, com.cakebackoffice.clientsoap.contract.Order contractOrder) {
        this.remoteID = Long.valueOf(contractOrder.id);
        if (contractOrder.client != null)
            this.client = new Client(contractOrder.client);
        this.corporateComments = contractOrder.comments;
        if (contractOrder.deliveryAddress != null)
            this.deliveryPlace = new Place(contractOrder.deliveryAddress);
        if (contractOrder.deliveryType != null)
            this.deliveryType = new DeliveryType(contractOrder.deliveryType);
        if (contractOrder.billingAddress != null)
            this.invoicingPlace = new Place(contractOrder.billingAddress);
        this.isTracked = contractOrder.isTracked;
        if (contractOrder.paiementType != null)
            this.paymentType = new PaymentType(contractOrder.paiementType);
        if (contractOrder.contentProductType != null) {
            List<com.cakebackoffice.clientsoap.contract.ProductType> productTypesList = contractOrder.contentProductType;
            for (ProductType productType : productTypesList) {
                List<LocalPriceHT> localprices = productType.localPrices;
                float localPrice = 42f;
                if (localprices != null) {
                    for (LocalPriceHT localPriceHT : localprices) {
                        if (com.cakebackoffice.Model.Store.getLocalStore(context) != null && localPriceHT.storeId == com.cakebackoffice.Model.Store.getLocalStore(context).getRemoteID()) {
                            localPrice = localPriceHT.storeId;
                        }
                    }
                }
//                float vat = productType.vat;
                com.cakebackoffice.Model.ProductType productTypeModel;
                if ((productTypeModel = com.cakebackoffice.Model.ProductType.getOneFromRemoteID(context, productType.id)) == null) {
                    productTypeModel = new com.cakebackoffice.Model.ProductType(context, productType);
                    productTypeModel.saveToDatabase(context);
                }
                this.getUnitarySaleList().add(new UnitarySale(localPrice, 19.6f, productTypeModel, null));
            }
        }     /*
        if (contractOrder.contentMenuType != null)
            List<com.cakebackoffice.clientsoap.contract.MenuType> menuTypeList = new ArrayList<MenuType>(Arrays.asList(contractOrder.contentMenuType));
          */
    }


    public Long getRemoteID() {
        return remoteID;
    }

    public void setRemoteID(Long remoteID) {
        this.remoteID = remoteID;
    }

    public Order(Long idDB, Client client, Address address, List<UnitarySale> unitarySaleList, Date orderDate) {
        //constructeur a virer des qu'il sert plus a rien
    }

    //créer et update les lignes de commande depuis les ventes unitaires

    public List<OrderLine> getOrderLines() throws Exception {
        int flag = 0;                 //permet de checker si la ligne doit être faite
        boolean isMenu = false, isProduct = false;    // détermine si la unitarysale concerne un produit ou un menu
        this.orderLines.clear();
        for (UnitarySale u : this.unitarySaleList) {
            flag = 0;
            isMenu = false;
            isProduct = false;
            OrderLine r = null;
            //on vérifie si une ligne de commande correspondante existe
            Iterator<OrderLine> it = this.orderLines.iterator();
            while ((flag == 0) && (it.hasNext())) {
                r = it.next();
                //si c'est un produit
                if ((r.isProduct()) && (u.isProduct()) && (r.getProductType().getIdDB().equals(u.getProductType().getIdDB())) && (r.getUnitaryPrice() == u.getPrice())) {
                    flag++;
                    isProduct = true;
                }
                //si c'est un menu
                if ((r.isMenu()) && (u.isMenu()) && (r.getMenuType().getIdDB().equals(u.getMenuType().getIdDB())) && (r.getUnitaryPrice() == u.getPrice())) {
                    flag++;
                    isMenu = true;
                }
            }

            if (flag == 0) {
                //CREATION
                //si c'est un produit
                if (u.isProduct()) {
                    OrderLine newOrderLine = new OrderLine(u, this);
                    newOrderLine.setTag(orderLines.size());
                    this.orderLines.add(newOrderLine);
                } else if (u.isMenu()) {
                    OrderLine newOrderLine = new OrderLine(u, this);
                    newOrderLine.setTag(orderLines.size());
                    this.orderLines.add(newOrderLine);
                } else {
                    throw new Exception("WTF !!! C'est ni un Produit, ni un Menu ><");
                }
            } else {
                //UPDATE

                //si elle existe, on la complète
                //on se fiche de savoir ce que c'est (menu/produit)
                r.getUnitarySales().add(u);
            }

            Collections.sort(this.orderLines);

            //NOTE GESTION DES PRODUIST COMPRIS DANS LES MENUS
            //attention, manque la gestion des produits étant inclus dans un menu... comment gère-t-on les prix à ce moment ?
            //je propose de mettre un typeMenu ET un typeProduit lorsqu'un produit est compris dans un menu. Il faudra mettre son prix à zero.
            //à ces produits là correspondront une vente unitaire et une orderline d'un menu qui a le prix total. Cette fonctionnalité n'est pas implémentée ici
            //mais le code présent tient compte de cette possibilité dans les conditions
        }

        return this.orderLines;
    }


    public OrderPriority getPriority() {
        if (TimeElapsed() < 1 * 60 * 1000) {
            return (OrderPriority.VLow);
        }

        if (TimeElapsed() < 3 * 60 * 1000) {
            return (OrderPriority.Low);
        }

        if (TimeElapsed() < 10 * 60 * 1000) {
            return (OrderPriority.Normal);
        }

        if (TimeElapsed() < 15 * 60 * 1000) {
            return (OrderPriority.High);
        }

        return (OrderPriority.VHigh);

    }

    public Date getDeliveryDate() {
        if (this.orderDate != null && (this.deliveryDate == null || this.deliveryDate.getTime() < this.orderDate.getTime())) {
            return orderDate;
        }
        return deliveryDate;
    }

    public void setDeliveryDate(Date deliveryDate) {
        this.deliveryDate = deliveryDate;
    }

    public DeliveryType getDeliveryType() {
        return deliveryType;
    }

    public void setDeliveryType(DeliveryType deliveryType1) {
        this.deliveryType = deliveryType1;
    }

    public boolean isTracked() {
        return isTracked;
    }

    public void setTracked(boolean tracked) {
        isTracked = tracked;
    }

    public String getCorporateComments() {
        return corporateComments;
    }

    public void setCorporateComments(String corporateComments) {
        this.corporateComments = corporateComments;
    }

    public Long TimeElapsed() {

        Date now = new Date();
        return (now.getTime() - this.getOrderDate().getTime());


    }

    public void setUnitarySaleList(List<UnitarySale> u) {
        this.unitarySaleList = u;
    }

    public Client getClient() {
        if (client == null) {
            client = new Client("John", "Doe", "0696969693");
        }
        return client;
    }

    public void setClient(Client client) {
        this.client = client;
    }

    public Address getAddress() {
        return this.deliveryPlace.getAddress();
    }

    public void setAddress(Address address) {
        this.deliveryPlace.setAddress(address);
    }

    public List<UnitarySale> getUnitarySaleList() {
        if (unitarySaleList == null) {
            unitarySaleList = new ArrayList<UnitarySale>();
        }
        return unitarySaleList;
    }

    public Float getTotalAmountTTC() {
        float totalAmount = 0;
        for (UnitarySale u : this.unitarySaleList) {
            totalAmount += u.getPrice() * (1 + u.getVAT() / 100);   //VAT !!!
        }
        return totalAmount;
    }

    public Integer getNumberOfProduct() {
        return unitarySaleList.size();
    }

    public Date getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(Date orderDate) {
        this.orderDate = orderDate;
    }

    @Override
    public ContentValues getValues() {
        ContentValues values = new ContentValues();
        values.put(OrderTable.REMOTE_ID, this.getRemoteID());
        values.put(OrderTable.ID_CLIENT, this.getClient() != null ? this.getClient().getIdDB() : null);
        values.put(OrderTable.ID_DELIVERYPLACE, this.getDeliveryPlace() != null ? this.getDeliveryPlace().getIdDB() : null);
        values.put(OrderTable.ID_BILLINGPLACE, this.getInvoicingPlace() != null ? this.getInvoicingPlace().getIdDB() : null);
        values.put(OrderTable.DATE, this.getOrderDate() != null ? this.getOrderDate().getTime() : null);
        values.put(OrderTable.DELIVERYDATE, this.getDeliveryDate() != null ? this.getDeliveryDate().getTime() : null);
        values.put(OrderTable.ISTRACKED, this.isTracked());
        values.put(OrderTable.CORPORATECOMMENTS, this.corporateComments);
        values.put(OrderTable.ID_PAYMENTYPE, this.getPaymentType() != null ? this.getPaymentType().getIdDB() : null);
        values.put(OrderTable.ID_DELIVERYTYPE, this.getDeliveryType() != null ? this.getDeliveryType().getIdDB() : null);
        return values;
    }

    @Override
    public void setIdDB(Long id) {
        this.idDB = id;
    }

    public Long getIdDB() {
        return idDB;
    }

    @Override
    public void saveToDatabase(Context context) {
        //Protection anti-doublons
        Order bis = null;
        if (this.getIdDB() == null && this.getRemoteID() != null && (bis = Order.getOneFromRemoteID(context, this.getRemoteID())) != null) {
            this.setIdDB(bis.getIdDB());
        }
        if (this.getClient() != null) {
            this.getClient().saveToDatabase(context);
        }
        if (this.getDeliveryPlace() != null) {
            this.getDeliveryPlace().saveToDatabase(context);
        }
        if (this.getInvoicingPlace() != null) {
            this.getInvoicingPlace().saveToDatabase(context);
        }
        if (this.getDeliveryType() != null) {
            this.getDeliveryType().saveToDatabase(context);
        }
        if (this.getUnitarySaleList() != null) {
            for (UnitarySale u : this.getUnitarySaleList()) {
                u.saveToDatabase(context);
            }
        }

        DataSource dataSource = new DataSource(context);
        dataSource.open();
        if (this.getIdDB() == null) {
            dataSource.insert(this, OrderTable.getInstance());
        } else {
            dataSource.update(this, OrderTable.getInstance());
            dataSource.delete(this, Order_has_UnitarySale.getInstance(), Order_has_UnitarySale.ID_ORDER);
        }
        {
            for (UnitarySale u : this.unitarySaleList) {
                dataSource.insert(Order_has_UnitarySale.getInstance(), this.getIdDB(), u.getIdDB());
            }
        }
        dataSource.close();

    }

    @Override
    public void removeFromDatabase(Context context) {
        if (this.getIdDB() != null) {
            DataSource dataSource = new DataSource(context);
            dataSource.open();
            dataSource.delete(this, OrderTable.getInstance());
            dataSource.delete(this, Order_has_UnitarySale.getInstance(), Order_has_UnitarySale.ID_ORDER);
            dataSource.close();
        }
    }

    public static Order getOne(Context context, Long idDB) {
        DataSource dataSource = new DataSource(context);
        dataSource.open();
        Cursor cursor = dataSource.fetchOne(idDB, OrderTable.getInstance());
        cursor.moveToFirst();
        Order item = null;
        while (!cursor.isAfterLast()) {
            item = new Order(dataSource, cursor);
            cursor.moveToNext();
        }
        cursor.close();
        dataSource.close();
        return item;
    }

    public static Order getOneFromRemoteID(Context context, Long idDB) {
        DataSource dataSource = new DataSource(context);
        dataSource.open();
        Cursor cursor = dataSource.fetchOneFromRemoteID(idDB, OrderTable.getInstance());
        cursor.moveToFirst();
        Order item = null;
        while (!cursor.isAfterLast()) {
            item = new Order(dataSource, cursor);
            cursor.moveToNext();
        }
        cursor.close();
        dataSource.close();
        return item;
    }

    public static List<Order> getAll(Context context) {
        List<Order> result = new ArrayList<Order>();
        DataSource dataSource = new DataSource(context);
        dataSource.open();
        Cursor cursor = dataSource.fetchAll(OrderTable.getInstance());
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            result.add(new Order(dataSource, cursor));
            cursor.moveToNext();
        }
        dataSource.close();
        return result;
    }

    public void setIdDB(long idDB) {
        this.idDB = idDB;
    }

    static Order getOne(DataSource dataSource, Long idDB) {
        Cursor cursor = dataSource.fetchOne(idDB, OrderTable.getInstance());
        cursor.moveToFirst();
        Order item = null;
        while (!cursor.isAfterLast()) {
            item = new Order(dataSource, cursor);
            cursor.moveToNext();
        }
        cursor.close();
        return item;
    }

    static List<Order> getAll(DataSource dataSource) {
        List<Order> result = new ArrayList<Order>();
        Cursor cursor = dataSource.fetchAll(OrderTable.getInstance());
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            result.add(new Order(dataSource, cursor));
            cursor.moveToNext();
        }
        return result;
    }

    public Place getDeliveryPlace() {
        return deliveryPlace;
    }

    public void setDeliveryPlace(Place deliveryPlace) {
        this.deliveryPlace = deliveryPlace;
    }

    public PaymentType getPaymentType() {
        return paymentType;
    }

    public void setPaymentType(PaymentType paymentType) {
        this.paymentType = paymentType;
    }

    public Place getInvoicingPlace() {
        return invoicingPlace;
    }

    public void setInvoicingPlace(Place invoicingPlace) {
        this.invoicingPlace = invoicingPlace;
    }


    public static class saveAsyncSaveTask extends AsyncTask<Order, Integer, Order> {
        ProgressDialog progressDialog;
        Context context;

        public saveAsyncSaveTask(Context context) {
            this.context = context;
        }

        public Context getContext() {
            return context;
        }

        public void setContext(Context context) {
            this.context = context;
        }

        @Override
        protected Order doInBackground(Order... orders) {
            orders[0].saveToDatabase(getContext());
            return orders[0];
        }

        @Override
        protected void onPreExecute() {
            progressDialog = ProgressDialog.show(getContext(), "", "Enregistrement ...");
        }

        @Override
        protected void onPostExecute(Order order) {
            progressDialog.dismiss();
        }
    }

    public class getFollowingAsyncTask extends AsyncTask<Integer, Integer, Integer> {
        ProgressDialog progressDialog;
        Context context;
        Store localStore;

        public getFollowingAsyncTask(Context context) {
            this.context = context;
            localStore = Store.getLocalStore(context);
        }

        public Context getContext() {
            return context;
        }

        public void setContext(Context context) {
            this.context = context;
        }

        @Override
        protected Integer doInBackground(Integer... ints) {
            CakeBackOfficeSoapClient Serveur = new CakeBackOfficeSoapClient();
            com.cakebackoffice.clientsoap.contract.Order[] orderList = null;
            /*
            try {
                orderList = Serveur.getFollowingOrderList(Integer.parseInt(localStore.getRemoteID().toString()));
                new OurSQLiteOpenHelper(context).truncateTable(StoreTable.getInstance());
                for (com.cakebackoffice.clientsoap.contract.Order contractOrder : orderList) {
                    Order modelStore = new Order(this.context, contractOrder);
                }
                return 1;

            } catch (SoapComException e) {
                new AlertDialog.Builder(this.getContext()).setMessage(e.getMessage()).create();
            } catch (SoapClientException e) {
                new AlertDialog.Builder(this.getContext()).setMessage(e.getMessage()).create();
            }  */
            return 0;

        }

        @Override
        protected void onPreExecute() {
            progressDialog = ProgressDialog.show(getContext(), "Order", "Recupération des dernières commandes ...");
        }

        @Override
        protected void onPostExecute(Integer order) {
            progressDialog.dismiss();
        }
    }

}
